<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">aaa</div>

  <script>
    // 定义一个副作用函数桶，存放一个个的副作用函数
    // 这里bucket就不能是一个set对象，而必须是一个map对象
    const bucket = new Map()

    // 定义一个全局变量。保存当前正在执行的副作用函数
    let activeEffect = null

    function isObject(value) {
      return typeof value === 'object' && value !== null
    }
    /** 
     * 创建响应式数据
     * @param [object ]:普通对象
     * @return [Proxy ]：代理对象
    */
    function reactive(data) {
      if (!isObject(data)) return
      return new Proxy(data, {
        get(target, key) {
          // console.log(target, key);
          // 只有activeEffect有值时（保存的是副作用函数），才添加到桶中
          // 修改副作用函数添加的规则，根据key值来添加不同的副作用函数
          if (activeEffect) {
            let depSet= new Set()
            if (!bucket.get(key)) {
              bucket.set(key, depSet)
            }
            depSet.add(activeEffect)
          }
          return target[key]
        },
        set(target, key, value) {
          target[key] = value
          // 依次取出每个函数，都执行一次
          let depSet = bucket.get(key)
          if (depSet) {
            depSet.forEach(element => {
              element()
            });
          }
          return true
        }
      })
    }

    /** 
     * 注册副作用函数
     * @param [object ]:需要注册的副作用函数
     * 
    */
    function registEffect(fn) {
      if (typeof fn !== 'function') return
      // 记录正在执行的副作用函数
      activeEffect = fn
      // 调用副作用函数
      fn()
      // 重置全局变量
      activeEffect = null
    }
    // 定义一个响应式数据：触发者
    const state = reactive({ name: 'xiaopang', age: 3 })

    // 定义一个副作用函数：响应者
    function effectName() {
      console.log("effectName被执行了", state.name);
      app.innerHTML = state.name
    }

    registEffect(effectName)
    // activeEffect = effectName
    // effectName()
    // activeEffect = null

    function effectAge() {
      console.log("effectAge被执行了", state.age);
    }

    registEffect(effectAge)
    // activeEffect = effectAge
    // effectAge()
    // activeEffect = null

    // 当数据改变的时候，重新执行对应副作用函数effect
    setTimeout(() => {
      state.name = "顿健康"
    }, 1000)

  </script>
</body>

</html>